#include "acquisition.h"

void launch_acquisition(module* mdl, const int port) {
	server srv = *(mdl->srv);
	strcpy(srv.name, mdl->name);
	srv.my_port=port;
	srv.isAlive = 1;
	/*
	 * Identification au serveur interboursier
	 */
	int interb_sockfd;
	struct sockaddr_in interb_addr; /* adresse du serveur interboursier */
	struct hostent *he;

	if ((he=gethostbyname("localhost")) == NULL) {
		herror("gethostbyname");
		exit(1);
	}

	if ((interb_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	interb_addr.sin_family = AF_INET; /* host byte order */
	interb_addr.sin_port = htons(1200); /* short, network byte order */
	interb_addr.sin_addr = *((struct in_addr *)he->h_addr);
	bzero(&(interb_addr.sin_zero), 8); /* zero pour le reste de struct */

	if (connect(interb_sockfd,( struct sockaddr *)&(interb_addr), sizeof(struct sockaddr)) == -1) {
		log_srv(&srv,"impossible de se connecter au serveur interboursier");
		exit(1);
	}
	char login[9];
	sprintf(login,"%d:%d", mdl->bourse_id, srv.my_port);
	while(strlen(login)<9){
		char tmpx[9]; strcpy(tmpx,login);
		sprintf(tmpx,"0%s",login); strcpy(login,tmpx);
	}
	if (send(interb_sockfd, login, strlen(login), 0) == -1) {
		log_srv(&srv, "erreur lors de l'envoi du message vers le serveur interboursier");
		exit(1);
	}
	close(interb_sockfd);

	if ((srv.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}
	srv.local_addr.sin_family = AF_INET; /* host byte order */
	srv.local_addr.sin_port = htons(port); /* short, network byte order */
	srv.local_addr.sin_addr.s_addr = INADDR_ANY; /* auto-remplissage avec mon IP */
	bzero(&(srv.local_addr.sin_zero), 8); /* zero pour le reste de struct */

	if (bind(srv.sockfd,( struct sockaddr *)&(srv.local_addr),sizeof(struct sockaddr))== -1) {
		perror("bind");
		exit(1);
	}

	if (listen(srv.sockfd, 5) == -1) { // on choisit un nombre max de connexions = 5
		perror("listen");
		exit(1);
	}
	char tmp[128];
	sprintf(tmp,"créé.");
	log_srv(&srv,tmp);
	if(!fork()) { /* fils première génération - permet de revenir de la méthode par contre créé des zombies */
		while(1) { // boucle d' accept() pour recevoir les connexions
			srv.sin_size = sizeof(struct sockaddr_in);
			int new_fd; // descripteur lié au socket de la connexion courante
			if ((new_fd = accept(srv.sockfd, (struct sockaddr *)&(srv.remote_addr),
					&(srv.sin_size))) == -1) {
				perror("accept");
				continue;
			}
			if(!srv.isAlive) {
				close(new_fd); //si une connexion arrive alors que le programme est terminé, on sort
				break; return;
			}
			char tmp[128];
			sprintf(tmp, "connexion entrante depuis %s:%d",inet_ntoa(srv.remote_addr.sin_addr),ntohs(srv.remote_addr.sin_port));
			log_srv(&srv,tmp);
			if (!fork()) { /* fils seconde génération - permet d'être multiclient */
				if(!srv.isAlive) {
					close(new_fd); //si une connexion arrive alors que le programme est terminé, on sort
					return;
				}
				char answer[MAXRECVDATA];
				/*sprintf(answer,"Serveur %s.\n", srv.name);
				if (send(new_fd, answer, strlen(answer), 0) == -1)
					perror("send");*/

				srv.recvdata = (msg*) malloc (sizeof (msg));
				char recvdata[MAXRECVDATA];
				bzero(srv.recvdata,sizeof (msg));
				if ((srv.numbytes=recv(new_fd, recvdata, MAXRECVDATA, 0)) == -1) {
					perror("recv");
					log_srv(&srv,"erreur lors du recv!");
					exit(1);
				}
				srv.recvdata = str_to_msg(recvdata);
				if(srv.recvdata==NULL) {
					log_srv(&srv,"réception d'un message non valide");
					close(new_fd);
				}
				sprintf(tmp,"%d octets reçu par %s %s:%d",srv.numbytes,srv.name, inet_ntoa(srv.remote_addr.sin_addr),ntohs(srv.remote_addr.sin_port));
				log_msg(tmp,srv.recvdata);
				//msg * rtn = (msg*) malloc(sizeof(msg)); // message retourné par process_msg
				char idbourse_str[5]; // identifiant de la bourse
				int idbourse;
				//process_msg(srv.recvdata,rtn);
				// TODO d'abord on regarde le type de message:
				strncpy(idbourse_str,srv.recvdata->action,4); // on copie l'id de la bourse du message
				idbourse_str[4]='\0';idbourse = atoi(idbourse_str);
				if(strcmp(&(srv.recvdata)->type[3],"c")==0){
					log_smth("j'ai reçu un accusé, je ne sais pas quoi faire avec.. désolé");
					exit(1);
				}
				int remote_port;
				if(idbourse==mdl->bourse_id) remote_port = srv.my_port+1;
				else remote_port = 1200;
				int dest_sockfd;
				struct sockaddr_in dest_addr; /* adresse du serveur d'exécution */
				if ((dest_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
					perror("socket");
					exit(1);
				}

				dest_addr.sin_family = AF_INET; /* host byte order */
				dest_addr.sin_port = htons(remote_port); /* short, network byte order */
				dest_addr.sin_addr = *((struct in_addr *)he->h_addr);
				bzero(&(dest_addr.sin_zero), 8); /* zero pour le reste de struct */
				log_smth("envoi des données vers le serveur de destination sur %s:%d",inet_ntoa(dest_addr.sin_addr),ntohs(dest_addr.sin_port));

				if (connect(dest_sockfd,( struct sockaddr *)&(dest_addr), sizeof(struct sockaddr)) == -1) {
					sprintf(tmp,"%s erreur de connexion",srv.name);
					perror(tmp);
					log_srv(&srv,"déjà connecté ou impossible de se connecter au serveur de destination");
					exit(1);
				}

				if (send(dest_sockfd, recvdata, strlen(recvdata), 0) == -1) {
					sprintf(tmp,"%s erreur d'envoi de message vers le serveur de destination",srv.name);
					perror(tmp);
					log_srv(&srv, "erreur lors de l'envoi du message vers le serveur de destination");
					exit(1);
				}
				// on attend désormais la réponse du serveur d'exécution
				bzero(srv.recvdata,sizeof (msg)); srv.numbytes=0;
				bzero(recvdata,sizeof (char)*MAXRECVDATA);
				if (srv.isAlive && (srv.numbytes=recv(dest_sockfd, recvdata, MAXRECVDATA, 0)) == -1) {
					perror("recv");
					log_srv(&srv,"erreur lors du recv!");
					sprintf(tmp,"Erreur lors de la réception de la confirmation du serveur de destination. Au revoir.\n");
					send(new_fd, tmp, strlen(tmp), 0);
					close(new_fd);
					exit(1);
				}
				srv.recvdata = str_to_msg(recvdata);
				if(srv.recvdata==NULL) {
					log_srv(&srv,"réception d'un message non valide");
					sprintf(tmp,"Erreur lors de la lecture du message reçu par le serveur de destination. Au revoir.\n");
					send(new_fd, tmp, strlen(tmp), 0);
					close(new_fd);
					exit(1);
				}
				sprintf(tmp,"%d octets reçu par %s %s:%d",srv.numbytes,srv.name, inet_ntoa(srv.remote_addr.sin_addr),ntohs(srv.remote_addr.sin_port));
				log_msg(tmp,srv.recvdata);
				close(dest_sockfd); // on ferme la connexion avec le serveur d'exécution
				// puis on renvoit cette réponse au terminal de base
				if (send(new_fd, recvdata, strlen(recvdata), 0) == -1) {
					sprintf(tmp,"%s erreur d'envoi du message vers le terminal",srv.name);
					perror(tmp);
					log_srv(&srv, "erreur lors de l'envoi du message vers le terminal");
					exit(1);
				}

				close(new_fd); // on ferme la connexion une fois le message reçu et renvoyé
			}
			while(waitpid(-1,NULL,WNOHANG) > 0); // nettoyage des processus fils
			close(new_fd);

		} // fin while du "accept"
	} // fin fils première génération


}

void process_msg(msg* damsg, msg* rtn);

void process(const char *emetteur, const char *type, const char *action,
		const char *valeur);
